from anime_downloader.sites.anime import Anime, AnimeEpisode, SearchResult
from anime_downloader.sites import helpers
import base64
import json
import logging
from anime_downloader.const import HEADERS

logger = logging.getLogger(__name__)


class AniMixPlay(Anime, sitename='animixplay'):
    sitename = 'animixplay'

    @classmethod
    def search(cls, query):
        # V3 not supported
        v1 = helpers.soupify(helpers.post("https://v1.nmtvjxdtx42qdwktdxjfoikjq.workers.dev/",
                                          data={"q2": query}, verify=False).json()['result']).select('p.name > a')
        v5 = helpers.soupify(helpers.post("https://cdn.animixplay.to/api/search/",
                                          data={"qfast": query}, verify=False).json()['result']).select('p.name > a')

        # v3 = helpers.soupify(helpers.post("https://v3.w0ltfgqz8y3ygjozgs4v.workers.dev/",
        #                                  data={"q3": query}, verify=False).json()['result'])

        # Gives 400 error on v3 and v4 if there's no results.
        # HTTPError doesn't seem to play along helpers hence why it's not expected.

        try:
            v4 = helpers.soupify(helpers.post("https://v4.w0ltfgqz8y3ygjozgs4v.workers.dev/",
                                              data={"q": query}, verify=False).json()['result']).select('p.name > a')
        except:
            v4 = []

        # Meta will be name of the key in versions_dict
        versions_dict = {'v1': v1, 'v4': v4, 'v5': v5}
        logger.debug('Versions: {}'.format(versions_dict))
        data = []
        for i in versions_dict:
            for j in versions_dict[i]:
                data.append(SearchResult(
                    title=j.text,
                    url='https://animixplay.com' + j.get('href'),
                    meta={'version': i},
                    meta_info={
                        'version_key_dubbed': '(Dub)',
                    }
                ))

        return data

    def _scrape_episodes(self):
        url = self.url
        soup = helpers.soupify(helpers.get(url))
        # v1 and v3 is embedded video player
        # v2 and v4 is json post request

        # ALL shit below really needs refactoring!
        if '/v2/' in self.url or '/v4/' in self.url:
            # Uses the id in the url and encodes it twice
            # NaN and N4CP9Eb6laO9N are permanent encoded variables found in
            # https://animixplay.com/assets/v4.min.js
            url_id = str.encode(self.url.split("/")[4])
            post_id = f'NaN{base64.b64encode(url_id).decode()}N4CP9Eb6laO9N'.encode()
            post_id = base64.b64encode(post_id).decode()
            data_id = 'id2' if '/v4/' in self.url else 'id'
            # In extremely rare cases the anime isn't loaded and must be generated by the server first
            try:
                data = (helpers.post('https://animixplay.com/raw/2ENCwGVubdvzrQ2eu4hBH',
                                     data={data_id: post_id}).json())
            # 400 HTTPError here
            except:
                if '/v4/' in self.url:
                    data = (helpers.post('https://animixplay.com/e4/5SkyXQULLrn9OhR',
                                         data={'id': url.split('/')[-1]}).json())['epstream']
                if '/v2' in self.url:
                    data = (helpers.post('https://animixplay.com/e2/T23nBBj3NfRzTQx',
                                         data={'id': url.split('/')[-1]}).json())['epstream']

            logger.debug(data)

            if '/v4/' in self.url:
                # Has a list of mp4 links.
                return data
            elif '/v2/' in self.url:
                # Has elaborate list for all metadata on episodes.
                episodes = []
                for i in data:
                    info_dict = i.get('src', None)
                    # Looks like mp4 is always first in the list
                    # Sometimes it returns None
                    if info_dict:
                        episodes.append(info_dict[0].get('file', ''))
                    else:
                        episodes.append('')
                return episodes

        else:
            # V5 and V1 are somewhat similar.

            servers = self.config['v5-servers']
            try:
                ep_list = soup.find('div', {'id': 'epslistplace'}).get_text()
                logger.debug(ep_list)
                jdata = json.loads(ep_list)
                if '/v1/' in self.url:
                    keyList = list(jdata.keys())
                    del keyList[0]
                    logger.debug(keyList)
                    return [jdata[x] for x in keyList if '.' in jdata[x]]
                else:
                    for i in servers:
                        if jdata.get(i):
                            return jdata.get(i)
                    return

            except json.decoder.JSONDecodeError:
                # Link generation
                url_dict = {'v5': '/e5/dZ40LAuJHZjuiWX', 'v1': '/e1/9DYiGVLD7ASqZ5p'}
                if '/v5/' in self.url:
                    version = 'v5'
                else:
                    version = 'v1'

                # Not sure if v5 id for data works.
                data = (helpers.post('https://animixplay.to' + url_dict[version],
                                     data={'id': url.split('/')[-1]}).json())['epstream']
                logger.debug('Data: {}'.format(data))
                if '/v1/' in self.url:
                    return [data[i] for i in data if i != 'eptotal']
                else:
                    for i in servers:
                        if jdata.get(i):
                            return jdata.get(i)
                    return

    def _scrape_metadata(self):
        self.title = helpers.soupify(helpers.get(self.url).text).select_one("span.animetitle").get_text()


class AniMixPlayEpisode(AnimeEpisode, sitename='animixplay'):
    def _get_sources(self):
        logger.debug(self.url)
        # These could be done with dict.
        if not self.url:
            return ''
        elif 'googleapis.com/' in self.url:
            return [('no_extractor', self.url)]
        elif 'https://4anime' in self.url:
            # VERY DIRTY!
            # As extractors cannot save headers which is essentials for 4anime this code cannot be moved
            # to extractors which means it has to be copied here from _4anime.py.
            self.headers = {'user-agent': HEADERS[self.hash_url(self.url, len(HEADERS))]}
            resp = helpers.get(self.url, headers=self.headers)
            stream_url = helpers.soupify(resp).find('div', class_='videojs-desktop').find('source')['src']
            return [('no_extractor', stream_url)]
        elif 'mp4upload' in self.url:
            return [('mp4upload', self.url)]
        elif 'streamtape' in self.url:
            return [('streamtape', self.url)]
        else:
            return [('vidstream', self.url)]

    """
    Let's say the user generates link A with user agent X.
    Upon retry of command it'd normally use Link A (cached), but with user agent Y
    which would error because the user agent isn't consistent.

    This 'hashes' the url to generate a 'random' header which is consistent throughout multiple commands.
    """

    def hash_url(self, url, length):
        total = 0
        for i in url:
            total += ord(i)
        return total % length
